from django.db import models
from django import forms

from tags.templatetags.sanitize import sanitize
from apps.additions import ModelAdditionList
from apps.course.models import CourseForm

import sys
import logging

logger = logging.getLogger('pet.apps.additions.models')

def GetAdditions(model, course=None, instanceid=None):
    logger.debug("GetAdditions: Looking for additions with model=%s, course=%s, instanceid=%s",model, course, instanceid)
    AdditionList = ModelAddition.find(model=model,course=course)
    if not AdditionList: return None
    Additions = []
    if instanceid:
        for item in AdditionList:
            items = {
                'BOOL': BooleanAddition,
                'CHAR': CharAddition,
                'TEXT': TextAddition,
                'INT': IntAddition,
                'FLOAT': FloatAddition,
              }[item.type].objects.filter(modeladdition=item, instanceid=instanceid)
            Value = None
            if items: Value = items[0].value
            else: Value = item.default
            Additions.append((item,Value))
    else:
        for item in AdditionList:
            items = {
                'BOOL': BooleanAddition,
                'CHAR': CharAddition,
                'TEXT': TextAddition,
                'INT': IntAddition,
                'FLOAT': FloatAddition,
              }[item.type].objects.filter(modeladdition=item)
            Value = None
            if items: Value = items[0].value
            else: Value = item.default
            Additions.append((item,Value))
    if Additions: return Additions
    return None

def GetAdditionForms(model, instanceid, course=None, postinfo=None):
    AdditionList = ModelAddition.find(model=model,course=course)
    if not AdditionList:
        logger.debug("GetAdditionForms: No ModelAdditions found")
        return None
    Additions = []
    for item in AdditionList:
        instance = {
            'BOOL': BooleanAddition,
            'CHAR': CharAddition,
            'TEXT': TextAddition,
            'INT': IntAddition,
            'FLOAT': FloatAddition,
          }[item.type].objects.filter(modeladdition=item, instanceid=instanceid)
        if instance: instance = instance[0]
        else: instance = None
        Value = {
                'BOOL': BooleanAdditionForm,
                'CHAR': CharAdditionForm,
                'TEXT': TextAdditionForm,
                'INT': IntAdditionForm,
                'FLOAT': FloatAdditionForm,
              }[item.type](postinfo,required=item.required,instance=instance,prefix="addition_%s"%item.name)
        Value.fields['value'].label = item.name
        Value.fields['value'].help_text = item.description
        Value.instance.modeladdition = item
        Additions.append((item,Value))
    logger.debug("Additions found: %s",Additions)
    return Additions

# Create your models here.
class ModelAddition(models.Model):
    ADDITION_TYPES = (
    ('BOOL', 'Boolean (True or False)'),
    ('CHAR', 'Short Text (< 255 characters)'),
    ('TEXT', 'Long Text (> 255 characters)'),
    ('INT', 'Integer (-100, 5, 0, 16, etc.)'),
    ('FLOAT', 'Float (3.1415926, -96.876, etc.'),
    )

    model = models.CharField(max_length=255)
    course = models.CharField(max_length=255)
    name = models.CharField(max_length=255, help_text="The name of the new field to add")
    required = models.BooleanField(default=False, help_text="If this field is required. If type is Boolean, requires that the boolean value be true")
    type = models.CharField(max_length=6,choices=ADDITION_TYPES)
    number = models.IntegerField(blank=True, help_text="(Optional) This is used to indicate the order that additions for this model will appear")
    description = models.TextField(blank=True, null=True, help_text="(Optional) A description of the purpose the new field serves")
    default = models.CharField(max_length=255, blank=True, null=True, help_text="(Optional) A default value for the field")
    
    def save(self, *args, **kwargs):
        self.name = sanitize(self.name)
        self.description = sanitize(self.description)
        super(ModelAddition,self).save(*args,**kwargs)
    @staticmethod
    def find(course, model=None, name=None):
        Additions = []
        Objects = ModelAddition.objects.all()
        if model: Objects = Objects.filter(model=model)
        if name: Objects = Objects.filter(name=name)
        if course:
            for item in Objects:
                if course in item.course.split(','):
                    Additions.append(item)
        else: Additions = list(Objects)
        if Additions:
            if len(Additions) == 1 and model and name: return Additions[0]
            logger.debug("Found additions %s",Additions)
            return(sorted(Additions,key=lambda item: item.number))
        logger.debug("No additions found with course=%s, model=%s, name=%s",course, model, name)
        return None
    @staticmethod
    def find_or_404(course, model=None, name=None):
        Result = ModelAddition.find(course, model, name)
        if not Result:
            if logger: logger.error('ModelAdditions not found for course %s, model %s, name %s',course,model,name)
            raise Http404
        return Result
    
    def __unicode__(self):
        return "%s.%s" % (self.model, self.name)
    
    def __init__(self, *args, **kwargs):
        super(ModelAddition,self).__init__(*args, **kwargs)
        if not self.default and self.type == "BOOL":
            self.default = "False"
    def save(self, *args, **kwargs):
        if not self.number:
            self.number = len(list(ModelAddition.objects.filter(model=self.model)))
        if not self.default and self.type == "BOOL":
            self.default = "False"
        super(ModelAddition,self).save(*args,**kwargs)
    class Meta:
        unique_together = ('model','name')
        
class ModelAdditionForm(CourseForm):
    model = forms.ChoiceField(choices=())
    def __init__(self, *args, **kwargs):
        super(ModelAdditionForm,self).__init__(*args, **kwargs)
        MODEL_CHOICES = tuple([(unicode(model.__name__), unicode(model._meta.verbose_name_plural).capitalize()) for model in ModelAdditionList])        
        self.fields['model'].choices = MODEL_CHOICES

    class Meta:
        model = ModelAddition
  
class Addition(models.Model):
    instanceid = models.CharField(max_length=255)
    modeladdition = models.ForeignKey(ModelAddition)
    
    def save(self,*args,**kwargs):
        self.value = sanitize(self.value)
        super(Addition,self).save(*args,**kwargs)
    class Meta:
        abstract = True
                
class AdditionForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        if "instance" in kwargs and kwargs["instance"] and kwargs["instance"].modeladdition:
            self.value = kwargs["instance"].modeladdition.default
        self.required = kwargs.pop("required",False)
        super(AdditionForm,self).__init__(*args, **kwargs)
        self.fields["value"].required = self.required
    class Meta:
        model = Addition
        exclude = ['modeladdition','instanceid']

class BooleanAddition(Addition):
    value = models.BooleanField()
class BooleanAdditionForm(AdditionForm):
    class Meta(AdditionForm.Meta):
        model = BooleanAddition

class CharAddition(Addition):
    value = models.CharField(max_length=255)
class CharAdditionForm(AdditionForm):
    class Meta(AdditionForm.Meta):
        model = CharAddition
        widgets = {
            'value': forms.TextInput(attrs={'size': 60}),
        }
     
class IntAddition(Addition):
    value = models.IntegerField()
class IntAdditionForm(AdditionForm):
    class Meta(AdditionForm.Meta):
        model = IntAddition

class FloatAddition(Addition):
    value = models.FloatField()
class FloatAdditionForm(AdditionForm):
    class Meta(AdditionForm.Meta):
        model = FloatAddition
    
class TextAddition(Addition):
    value = models.TextField()
class TextAdditionForm(AdditionForm):
    class Meta(AdditionForm.Meta):
        model = TextAddition

